/*
 usage:compile this module by make
       load module by command "sudo insmod workqueue_irq.ko irqn=1 devname=workqueue_irq"
       irqn:irq number;devname:device name.
       irqn=1:interrupt share with i8042 keyboard controller(PS/2 port)
              usb keyboard use lsusb and cat /proc/interrupts to find.
 */

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <linux/slab.h>

static int irqn;
static char* devname;

module_param(irqn,int,0644);
MODULE_PARM_DESC(irqn,"The share irq number.");
module_param(devname,charp,0644);
MODULE_PARM_DESC(devname,"The share irq name.");

static void shr_work_routine(struct work_struct *ws)
{
	printk("shr_work_routine of system_wq!\n");
}

static void slam_work_routine(struct work_struct *ws)
{
	printk("slam_work_routine of slam_wq!\n");
}

static struct work_struct * shr_work;
static DECLARE_WORK(slam_work,slam_work_routine);
static struct workqueue_struct * slam_wq;

static irqreturn_t workqueue_irq_handler(int irq,void * devid)
{
	printk("Enter workqueue_irq_handler!\n");
	printk("ISR devid:%d\n",(int)(*(int *)devid));

	schedule_work(shr_work);
        queue_work(slam_wq,&slam_work);

	printk("Leaving IRQ handler!\n");
	return IRQ_HANDLED;
}

static int __init workqueue_irq_init(void)
{
	printk("Enter workqueue_irq_init...\n");
	if(request_irq(irqn,workqueue_irq_handler,IRQF_SHARED,devname,&irqn) != 0)
	{
		printk("Request IRQ failed!\ndevname=%s,IRQ:%d\n",devname,irqn);
		return -1;
	}

	shr_work = kzalloc(sizeof(typeof(*shr_work)),GFP_KERNEL);
	INIT_WORK(shr_work,shr_work_routine);

	slam_wq = create_workqueue("slam_wq");
        
	printk("Exit workqueue_irq_init...\n");
	return 0;
}

static void __exit workqueue_irq_exit(void)
{
	printk("Enter workqueue_irq_exit...\n");
	flush_workqueue(slam_wq);
	free_irq(irqn,&irqn);
	destroy_workqueue(slam_wq);
	printk("Exit workqueue_irq_exit...\n");
}

module_init(workqueue_irq_init);
module_exit(workqueue_irq_exit);

MODULE_LICENSE("GPL");
